﻿using SerialPort通信.Properties;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SerialPort通信
{
    public partial class Form1 : Form
    {
        public enum ParityMethod
        {
            XOR异或,
            SUM8累加,
            SUM16大端,
            SUM16小端,
            CRC16大端,
            CRC16小端,
            ModbusCRC大端,
            ModbusCRC小端,
        }

        //串口对象
        private SerialPort serialPort = null;

        private Encoding encoding = Encoding.UTF8;

        private System.Timers.Timer AutoSendTimer = new System.Timers.Timer();

        private Settings settings = Settings.Default;

        public Form1()
        {
            InitializeComponent();
            InitalSetting();
        }

        private void InitalSetting()
        {
            string[] PortList = SerialPort.GetPortNames();
            if (PortList.Length > 0)
            {
                this.Port_Cmb.DataSource = PortList;
                this.Port_Cmb.SelectedIndex = 0;
            }

            //波特率
            string[] BaudList = new string[] { "2400", "4800", "9600", "19200", "38400" };
            this.Baud_Cmb.DataSource = BaudList;
            this.Baud_Cmb.SelectedIndex = 2;

            //校验位
            this.Parity_Cmb.DataSource = Enum.GetNames(typeof(Parity));
            this.Parity_Cmb.SelectedIndex = 0;

            //停止位
            this.Stop_Cmb.DataSource = Enum.GetNames(typeof(StopBits));
            this.Stop_Cmb.SelectedIndex = 1;

            //数据位
            int[] DataList = new int[] { 5, 6, 7, 8 };
            this.Data_Cmb.DataSource = DataList;
            this.Data_Cmb.SelectedIndex = 3;

            //校验方式
            this.ParityMethod_CB.DataSource = Enum.GetNames(typeof(ParityMethod));
            this.ParityMethod_CB.SelectedIndex = 0;

            //设置命令按钮
            this.Qucik01_Btn.Text = settings.Qucik01_Btn;
            this.Qucik01_Btn.Tag = settings.QucikCommand1;
            this.Qucik02_Btn.Text = settings.Qucik02_Btn;
            this.Qucik02_Btn.Tag = settings.QucikCommand2;
            this.Qucik03_Btn.Text = settings.Qucik03_Btn;
            this.Qucik03_Btn.Tag = settings.QucikCommand3;
            this.Qucik04_Btn.Text = settings.Qucik04_Btn;
            this.Qucik04_Btn.Tag = settings.QucikCommand4;
        }

        //串口状态
        private bool isOpen = false;

        public bool IsOpen
        {
            get { return isOpen; }
            set
            {
                isOpen = value;
                if (value)
                {
                    this.OpenBtn.Text = "关闭串口";
                }
                else
                {
                    this.OpenBtn.Text = "打开串口";
                }
            }
        }

        //发送字节计数
        private int totalSendNum = 0;

        public int TotalSendNum
        {
            get { return totalSendNum; }
            set
            {
                totalSendNum = value;
                this.tss_SendCount.Text = value.ToString();
            }
        }

        //接收字节计数
        private int totalReceiveNum = 0;

        public int TotalReceiveNum
        {
            get { return totalReceiveNum; }
            set
            {
                totalReceiveNum = value;
                this.tss_ReceiveCount.Text = value.ToString();
            }
        }

        public string SaveFile
        {
            get { return DateTime.Now.ToString("yyyyMMddHHmmss") + ".txt"; }
        }

        private int ClearLimitNum = 4096;

        private bool isPause = false;

        private bool IsPause
        {
            get { return isPause; }
            set
            {
                isPause = value;
                if (value)
                {
                    this.pause_Btn.Text = "继续接收";
                }
                else
                {
                    this.pause_Btn.Text = "暂停接收";
                }
            }
        }

        private void OpenBtn_Click(object sender, EventArgs e)
        {
            if (IsOpen)
            {
                // 移除事件处理器避免在关闭时触发
                serialPort.DataReceived -= SerialPort_DataReceived;
                //串口关闭
                if (serialPort == null && serialPort.IsOpen)
                {
                    this.serialPort.Close();
                }
                IsOpen = false;

                //应该写状态栏
                MessageBox.Show("串口关闭成功");
            }
            else
            {
                //串口打开
                //实例化对象
                serialPort = new SerialPort();
                try
                {
                    //设置串口属性
                    this.serialPort.PortName = this.Port_Cmb.Text.Trim();
                    this.serialPort.BaudRate = Convert.ToInt32(this.Baud_Cmb.Text.Trim());
                    this.serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), this.Parity_Cmb.Text.Trim(), true);
                    this.serialPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), this.Stop_Cmb.Text.Trim(), true);

                    this.serialPort.RtsEnable = this.RTS_Check.Checked;
                    this.serialPort.DtrEnable = this.DRT_Check.Checked;
                    this.serialPort.Encoding = this.encoding;

                    this.serialPort.ReceivedBytesThreshold = 1;

                    this.serialPort.DataReceived += SerialPort_DataReceived;

                    if (this.serialPort.IsOpen)
                    {
                        this.serialPort.Close();
                    }
                    this.serialPort.Open();

                    IsOpen = true;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("串口打开失败" + ex.ToString());
                }
            }
        }

        /// <summary>
        /// 串口接收事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (IsPause) return;

            this.BeginInvoke(new Action(() =>
            {
                try
                {
                    int receivedBytes = 0; // 实际接收的字节数
                    string result = string.Empty;

                    if (this.HexCheck.Checked)
                    {
                        // 十六进制模式
                        byte[] data = new byte[serialPort.BytesToRead];
                        receivedBytes = serialPort.Read(data, 0, data.Length);

                        // 更高效的十六进制转换
                        result = BitConverter.ToString(data).Replace("-", "").ToLower();
                        this.Rechive_Rtb.AppendText(result);
                    }
                    else
                    {
                        // 文本模式
                        result = this.serialPort.ReadExisting();
                        receivedBytes = this.serialPort.Encoding.GetByteCount(result);
                        this.Rechive_Rtb.AppendText(result + Environment.NewLine);
                    }

                    // 更新接收字节总数（数值累加）
                    UpdateReceiveCount(receivedBytes);
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"接收错误: {ex.Message}", "串口错误",
                                  MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    // 自动清空检查（放在finally确保始终执行）
                    if (this.AutoClear.Checked && this.Rechive_Rtb.Text.Length > ClearLimitNum)
                    {
                        this.Rechive_Rtb.Clear();
                    }
                }
            }));
        }

        // 专门处理接收计数更新的方法
        private void UpdateReceiveCount(int additionalBytes)
        {
            if (int.TryParse(tss_ReceiveCount.Text, out int currentCount))
            {
                tss_ReceiveCount.Text = (currentCount + additionalBytes).ToString();
            }
            else
            {
                // 初始值或无效值时设为当前字节数
                tss_ReceiveCount.Text = additionalBytes.ToString();
            }
        }

        /// <summary>
        /// 手动发送
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void HandSend_Btn_Click(object sender, EventArgs e)
        {
            SendData();
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        private void SendData()
        {
            int bytesSent = 0;
            bool success = false;

            try
            {
                if (this.Hex2_Check.Checked)
                {
                    // 十六进制模式
                    string temp = this.Send_RTB.Text.Replace(" ", "");
                    byte[] b = HexHelper.HexStringToByteArray(temp);
                    serialPort.Write(b, 0, b.Length);
                    bytesSent = b.Length;
                }
                else
                {
                    // 文本模式
                    string textToSend = this.Send_RTB.Text;
                    byte[] b = encoding.GetBytes(textToSend);
                    serialPort.Write(b, 0, b.Length);
                    bytesSent = b.Length;
                }
                success = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show($"发送失败: {ex.Message}", "错误",
                MessageBoxButtons.OK, MessageBoxIcon.Error);
                IsOpen = false;
            }
            finally
            {
                // 更新发送计数（无论成功与否）
                if (success)
                {
                    totalSendNum += bytesSent;
                    this.tss_SendCount.Text = totalSendNum.ToString();
                }
            }
        }

        private void ClearSend_Btn_Click(object sender, EventArgs e)
        {
            this.Send_RTB.Clear();
        }

        /// <summary>
        /// 定时发送
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AutoSend_Check_CheckedChanged(object sender, EventArgs e)
        {
            if (IsOpen == false && this.AutoSend2_Check.CheckState == CheckState.Checked)
            {
                this.AutoSend2_Check.CheckState = CheckState.Unchecked;

                //停止定时器
                this.AutoSendTimer.Enabled = false;

                MessageBox.Show("自动发送失败,串口未打开");
                return;
            }
            if (IsOpen == true && this.AutoSend2_Check.CheckState == CheckState.Checked)
            {
                //禁用手动发送
                this.HandSend_Btn.Enabled = false;
                //获取时间周期
                int interval = 0;
                if (int.TryParse(this.txt.Text.Trim(), out interval))
                {
                    if (interval < 1 || interval > 60000)
                    {
                        interval = 1000;
                        txt.Text = "1000";
                        MessageBox.Show("周期设置过大，限制为1000ms");
                    }
                    this.AutoSendTimer.Interval = interval;

                    this.AutoSendTimer.Elapsed += AutoSendTimer_Elapsed;
                    this.AutoSendTimer.Enabled = true;

                    //禁用周期设定
                    this.txt.Enabled = false;
                }
                else
                {
                    this.AutoSend2_Check.CheckState = CheckState.Unchecked;
                    //停止定时器
                    this.AutoSendTimer.Enabled = false;
                    return;
                }
            }
            else
            {
                this.HandSend_Btn.Enabled = true;
                this.txt.Enabled = true;
                //this.AutoSendTimer.Elapsed -= AutoSendTimer_Elapsed;
                this.AutoSendTimer.Enabled = false;
            }
        }

        private void AutoSendTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            Invoke(new Action(() =>
            {
                SendData();
            }));
        }

        private void OpenFile_Btn_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();

            //设置OpenFileDialog
            openFileDialog.Title = "请选择要发送的文件";
            openFileDialog.Filter = "文本文件(*.txt)|*.txt|二进制文件(*.bin)|*.bin|HEX文件(*.hex)|*.hex";
            openFileDialog.RestoreDirectory = true;

            //打开设置OpenFileDialog
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                //把十六进制按钮取消
                this.Hex2_Check.Checked = false;

                //获取文件的名称并显示
                string fileName = openFileDialog.FileName;
                this.FileName.Text = fileName;

                //读取内容显示
                StreamReader streamReader = new StreamReader(fileName, encoding);
                this.Send_RTB.Text = streamReader.ReadToEnd();
            }
        }

        private void SendFile_Btn_Click(object sender, EventArgs e)
        {
            if (IsOpen)
            {
                if (this.FileName.Text.Length == 0)
                {
                    MessageBox.Show("请先选择要发送的文件");
                    return;
                }
                byte[] byteMessage = encoding.GetBytes(this.Send_RTB.Text);

                int sendcount = byteMessage.Length / 4096;
                int sendRemaind = byteMessage.Length % 4096;
                try
                {
                    //循环发送
                    for (int i = 0; i < sendcount; i++)
                    {
                        this.serialPort.Write(byteMessage, i * 4096, 4096);
                        Thread.Sleep(50);
                    }
                    //最后一次发送
                    if (sendRemaind > 0)
                    {
                        this.serialPort.Write(byteMessage, sendcount * 4096, sendRemaind);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("发送文件失败" + ex);
                    return;
                }
            }
            else
            {
            }
        }

        private void HandAuto_Click(object sender, EventArgs e)
        {
            this.Rechive_Rtb.Clear();
        }

        private void Pause_Btn_Click(object sender, EventArgs e)
        {
            IsPause = !IsPause;
        }

        private void SelectPath_Btn_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();

            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                this.txt_PathSelect.Text = folderBrowserDialog.SelectedPath;
            }
        }

        private void SaveData_Btn_Click(object sender, EventArgs e)
        {
            if (this.Rechive_Rtb.Text.Length == 0)
            {
                MessageBox.Show("接收数据为空，请检查!");
                return;
            }
            if (this.txt_PathSelect.Text.Length == 0)
            {
                MessageBox.Show("请先设置要保存的路径!");
                return;
            }
            string SavePath = this.txt_PathSelect.Text + "\\" + SaveFile;

            //创建写入器
            StreamWriter sw = new StreamWriter(SavePath);
            sw.Write(this.Rechive_Rtb.Text);
            sw.Flush();
            sw.Close();

            MessageBox.Show("文件" + SaveFile + "保存成功");
        }

        private void CLearCount_Btn_Click(object sender, EventArgs e)
        {
            this.tss_ReceiveCount.Text = "0";
            this.tss_SendCount.Text = "0";
        }

        private void Qucik_Btn_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                if (sender is Button btn)
                {
                    //打开设置窗体并传值
                    FrmQuickSet frmQuickSet = new FrmQuickSet(btn.Text, btn.Tag?.ToString());
                    if (frmQuickSet.ShowDialog() == DialogResult.OK)
                    {
                        //获取设置的最新值
                        btn.Text = frmQuickSet.CmdName;
                        btn.Tag = frmQuickSet.CmdContent;

                        //保存配置

                        switch (btn.Name)
                        {
                            case "Qucik01_Btn":
                                settings.Qucik01_Btn = frmQuickSet.CmdName;
                                settings.QucikCommand1 = frmQuickSet.CmdContent;
                                break;

                            case "Qucik02_Btn":
                                settings.Qucik02_Btn = frmQuickSet.CmdName;
                                settings.QucikCommand2 = frmQuickSet.CmdContent;
                                break;

                            case "Qucik03_Btn":
                                settings.Qucik03_Btn = frmQuickSet.CmdName;
                                settings.QucikCommand3 = frmQuickSet.CmdContent;
                                break;

                            case "Qucik04_Btn":
                                settings.Qucik04_Btn = frmQuickSet.CmdName;
                                settings.QucikCommand4 = frmQuickSet.CmdContent;
                                break;

                            default:
                                break;
                        }

                        settings.Save();
                    }
                }
            }
        }

        private void Qucik_Btn_Click(object sender, EventArgs e)
        {
            if (IsOpen)
            {
                if (sender is Button btn)
                {
                    if (btn.Tag != null && btn.Tag.ToString().Length > 0)
                    {
                        string cmdContent = btn.Tag.ToString();
                        this.Send_RTB.Text = cmdContent;
                        cmdContent = cmdContent.Replace(" ", "");
                        this.serialPort.Write(HexHelper.HexStringToByteArray(cmdContent), 0, HexHelper.GetHexByteCount(cmdContent));
                    }
                    else
                    {
                        MessageBox.Show("发送失败,发送命令未设置");
                    }
                    //string cmdContent = string.Empty;
                    //switch (btn.Name)
                    //{
                    //    case "Qucik01_Btn":
                    //        cmdContent =
                    //        break;
                    //}
                }
            }
            else
            {
                MessageBox.Show("发送失败,串口未打开");
            }
        }

        /// <summary>
        /// 命令模式
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SendCommand_Btn_Click(object sender, EventArgs e)
        {
            bool DataVerify = true;
            if (this.Head_CB.Checked)
            {
                DataVerify &= VerifyHexString(this.Head_Txt.Text.Trim());
            }
            if (this.Data_CB.Checked)
            {
                DataVerify &= VerifyHexString(this.Data_Txt.Text.Trim());
            }
            if (this.Tail_CB.Checked)
            {
                DataVerify &= VerifyHexString(this.Tail_Txt.Text.Trim());
            }
            if (!DataVerify)
            {
                MessageBox.Show("命令模式填写的数据格式不正确！");
                return;
            }

            if (IsOpen)
            {
                string fullCmd = string.Empty;

                //是否选择帧头
                if (this.Head_CB.Checked)
                {
                    fullCmd += this.Head_Txt;
                }
                //是否选择数据
                if (this.Data_CB.Checked)
                {
                    fullCmd += this.Data_Txt;
                }
                //是否选择校验
                if (this.Check_CB.Checked)
                {
                    ParityMethod parityMethod = (ParityMethod)Enum.Parse(typeof(ParityMethod), this.ParityMethod_CB.Text, true);

                    switch (parityMethod)
                    {
                        case ParityMethod.XOR异或:
                            break;

                        case ParityMethod.SUM8累加:
                            break;

                        case ParityMethod.SUM16大端:
                            break;

                        case ParityMethod.SUM16小端:
                            break;

                        case ParityMethod.CRC16大端:
                            break;

                        case ParityMethod.CRC16小端:
                            break;

                        case ParityMethod.ModbusCRC大端:
                            break;

                        case ParityMethod.ModbusCRC小端:
                            break;

                        default:
                            break;
                    }
                }
            }
            else
            {
                MessageBox.Show("发送失败,串口未打开");
            }
        }

        /// <summary>
        /// 验证是否是十六进制字符串
        /// </summary>
        /// <param name="hex"></param>
        /// <returns></returns>
        private bool VerifyHexString(string hex)
        {
            string temp = hex.Replace(" ", "");
            return HexHelper.IsHexString(temp) && temp.Length % 2 == 0;
        }
    }
}